home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / var / lib / python-support / python2.6 / orca / gnomespeechfactory.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  32.0 KB  |  1,061 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''Provides a SpeechServer factory for gnome-speech drivers.'''
  5. __id__ = '$Id: gnomespeechfactory.py 4567 2009-02-16 22:13:55Z wwalker $'
  6. __version__ = '$Revision: 4567 $'
  7. __date__ = '$Date: 2009-02-16 17:13:55 -0500 (Mon, 16 Feb 2009) $'
  8. __copyright__ = 'Copyright (c) 2005-2008 Sun Microsystems Inc.'
  9. __license__ = 'LGPL'
  10. import logging
  11. log = logging.getLogger('speech')
  12. import gobject
  13. import Queue
  14. import threading
  15. import time
  16. import bonobo
  17. import ORBit
  18. import chnames
  19. import debug
  20. import orca
  21. import orca_state
  22. import punctuation_settings
  23. import settings
  24. import speech
  25. import speechserver
  26. from acss import ACSS
  27. from orca_i18n import _
  28. ORBit.load_typelib('GNOME_Speech')
  29. import GNOME.Speech as GNOME
  30. import GNOME__POA.Speech as GNOME__POA
  31.  
  32. def _matchLanguage(desired, actual):
  33.     """Compares a desired language to an actual language and returns
  34.     a numerical value representing the degree of match.  The expected
  35.     language format is a string similar to the following, where the
  36.     delimiter can be '-' '_' or '.':
  37.  
  38.       de-DE (German for Germany)
  39.       en-US (English as used in the United States)
  40.  
  41.     Additional extensions for variants or dialects are allowed as well.
  42.  
  43.     The return value is one of the following:
  44.  
  45.       0 - no match at all
  46.       1 - some match
  47.       2 - exact match
  48.     """
  49.     if desired == actual:
  50.         return 2
  51.     if not desired or not actual:
  52.         return 0
  53.     desired = desired.lower().replace('-', '_').replace('.', '_').split('_')
  54.     actual = actual.lower().replace('-', '_').replace('.', '_').split('_')
  55.     matchCount = 0
  56.     for i in range(0, min(len(desired), len(actual))):
  57.         if desired[i] == actual[i]:
  58.             matchCount += 1
  59.             continue
  60.         not actual
  61.     
  62.     if matchCount == len(desired):
  63.         return 2
  64.     if matchCount:
  65.         return 1
  66.     return 0
  67.  
  68.  
  69. class _SayAll:
  70.     
  71.     def __init__(self, iterator, context, utteranceId, progressCallback):
  72.         self.utteranceIterator = iterator
  73.         self.currentContext = context
  74.         self.idForCurrentContext = utteranceId
  75.         self.progressCallback = progressCallback
  76.  
  77.  
  78.  
  79. class _Speaker(GNOME__POA.Speech.SpeechCallback):
  80.     """Implements gnome-speech's SpeechCallback class.  The gnome-speech
  81.     server only allows one speech callback to be registered with a speaker
  82.     and there's no way to unregister it.  So...we need to handle stuff
  83.     like that on our own.  This class handles this for us and also delegates
  84.     all calls to the 'real' gnome speech speaker.
  85.     """
  86.     
  87.     def __init__(self, gnome_speaker, voice):
  88.         self.gnome_speaker = gnome_speaker
  89.         if settings.enableSpeechCallbacks:
  90.             gnome_speaker.registerSpeechCallback(self._this())
  91.         
  92.         self._Speaker__callbacks = []
  93.         self.voiceInfo = [
  94.             voice.name,
  95.             voice.language,
  96.             voice.gender]
  97.  
  98.     
  99.     def registerCallback(self, callback):
  100.         self._Speaker__callbacks.append(callback)
  101.  
  102.     
  103.     def deregisterCallback(self, callback):
  104.         self._Speaker__callbacks.remove(callback)
  105.  
  106.     
  107.     def notify(self, progressType, utteranceId, offset):
  108.         '''Called by GNOME Speech when the GNOME Speech driver generates
  109.         a callback.
  110.  
  111.         Arguments:
  112.         - progressType:  one of GNOME.Speech.speech_callback_speech_started,
  113.                          GNOME.Speech.speech_callback_speech_progress,
  114.                          GNOME.Speech.speech_callback_speech_ended
  115.         - utteranceId:   the id of the utterance (returned by say)
  116.         - offset:        the character offset into the utterance (for progress)
  117.         '''
  118.         for callback in self._Speaker__callbacks:
  119.             callback.notify(progressType, utteranceId, offset)
  120.         
  121.  
  122.     
  123.     def say(self, text):
  124.         if isinstance(text, unicode):
  125.             text = text.encode('UTF-8')
  126.         
  127.         return self.gnome_speaker.say(text)
  128.  
  129.     
  130.     def stop(self):
  131.         self.gnome_speaker.stop()
  132.  
  133.     
  134.     def getSupportedParameters(self):
  135.         return self.gnome_speaker.getSupportedParameters()
  136.  
  137.     
  138.     def getParameterValue(self, name):
  139.         return self.gnome_speaker.getParameterValue(name)
  140.  
  141.     
  142.     def setParameterValue(self, name, value):
  143.         return self.gnome_speaker.setParameterValue(name, value)
  144.  
  145.     
  146.     def unref(self):
  147.         
  148.         try:
  149.             self.gnome_speaker.unref()
  150.         except:
  151.             pass
  152.  
  153.  
  154.  
  155.  
  156. class SpeechServer(speechserver.SpeechServer):
  157.     '''Provides SpeechServer implementation for gnome-speech.'''
  158.     __activeServers = { }
  159.     
  160.     def __activateDriver(iid):
  161.         driver = bonobo.activation.activate_from_id(iid, 0, False)
  162.         driver = driver._narrow(GNOME.Speech.SynthesisDriver)
  163.         isInitialized = driver.isInitialized()
  164.         if not isInitialized:
  165.             isInitialized = driver.driverInit()
  166.         
  167.         if not isInitialized:
  168.             
  169.             try:
  170.                 driver.unref()
  171.             except:
  172.                 pass
  173.  
  174.             driver = None
  175.         
  176.         return driver
  177.  
  178.     __activateDriver = staticmethod(__activateDriver)
  179.     
  180.     def __createServer(iid):
  181.         server = None
  182.         if iid in SpeechServer._SpeechServer__activeServers:
  183.             server = SpeechServer._SpeechServer__activeServers[iid]
  184.         else:
  185.             driver = SpeechServer._SpeechServer__activateDriver(iid)
  186.             if driver:
  187.                 server = SpeechServer(driver, iid)
  188.                 SpeechServer._SpeechServer__activeServers[iid] = server
  189.             
  190.         return server
  191.  
  192.     __createServer = staticmethod(__createServer)
  193.     
  194.     def getFactoryName():
  195.         '''Returns a localized name describing this factory.'''
  196.         return _('GNOME Speech Services')
  197.  
  198.     getFactoryName = staticmethod(getFactoryName)
  199.     
  200.     def getSpeechServers():
  201.         '''Gets available speech servers as a list.  The caller
  202.         is responsible for calling the shutdown() method of each
  203.         speech server returned.
  204.         '''
  205.         knownServers = bonobo.activation.query("repo_ids.has('IDL:GNOME/Speech/SynthesisDriver:0.3')")
  206.         for server in knownServers:
  207.             if server.iid not in SpeechServer._SpeechServer__activeServers:
  208.                 
  209.                 try:
  210.                     SpeechServer._SpeechServer__createServer(server.iid)
  211.                 debug.printException(debug.LEVEL_WARNING)
  212.  
  213.                 continue
  214.         
  215.         return SpeechServer._SpeechServer__activeServers.values()
  216.  
  217.     getSpeechServers = staticmethod(getSpeechServers)
  218.     
  219.     def getSpeechServer(info = None):
  220.         '''Gets a given SpeechServer based upon the info.
  221.         See SpeechServer.getInfo() for more info.
  222.         '''
  223.         if info and info[1] in SpeechServer._SpeechServer__activeServers:
  224.             return SpeechServer._SpeechServer__activeServers[info[1]]
  225.         server = None
  226.         gservers = bonobo.activation.query("repo_ids.has('IDL:GNOME/Speech/SynthesisDriver:0.3')")
  227.         if len(gservers) == 0:
  228.             return None
  229.         gserver = None
  230.         if not info:
  231.             gserver = gservers[0]
  232.         else:
  233.             for s in gservers:
  234.                 if s.iid == info[1]:
  235.                     gserver = s
  236.                     break
  237.                     continue
  238.                 info[1] in SpeechServer._SpeechServer__activeServers
  239.             
  240.         if not gserver:
  241.             return None
  242.         server = None
  243.         
  244.         try:
  245.             server = SpeechServer._SpeechServer__createServer(gserver.iid)
  246.         except:
  247.             gserver
  248.             debug.printException(debug.LEVEL_WARNING)
  249.  
  250.         if not server:
  251.             for s in gservers:
  252.                 
  253.                 try:
  254.                     server = SpeechServer._SpeechServer__createServer(s.iid)
  255.                     if server:
  256.                         break
  257.                 continue
  258.                 debug.printException(debug.LEVEL_WARNING)
  259.                 continue
  260.  
  261.             
  262.         
  263.         return server
  264.  
  265.     getSpeechServer = staticmethod(getSpeechServer)
  266.     
  267.     def shutdownActiveServers():
  268.         '''Cleans up and shuts down this factory.
  269.         '''
  270.         for key in SpeechServer._SpeechServer__activeServers.keys():
  271.             server = SpeechServer._SpeechServer__activeServers[key]
  272.             server.shutdown()
  273.         
  274.  
  275.     shutdownActiveServers = staticmethod(shutdownActiveServers)
  276.     
  277.     def __init__(self, driver, iid):
  278.         speechserver.SpeechServer.__init__(self)
  279.         self._SpeechServer__speakers = { }
  280.         self._SpeechServer__pitchInfo = { }
  281.         self._SpeechServer__rateInfo = { }
  282.         self._SpeechServer__volumeInfo = { }
  283.         self._SpeechServer__driver = driver
  284.         self._SpeechServer__driverName = driver.driverName
  285.         self._SpeechServer__iid = iid
  286.         self._SpeechServer__sayAll = None
  287.         self._SpeechServer__isSpeaking = False
  288.         self._SpeechServer__eventQueue = Queue.Queue(0)
  289.         self._SpeechServer__gidleId = 0
  290.         self._SpeechServer__gidleLock = threading.Lock()
  291.         self._SpeechServer__lastResetTime = 0
  292.         self._SpeechServer__lastText = None
  293.         self.textCharIndices = []
  294.  
  295.     
  296.     def __getRate(self, speaker):
  297.         '''Gets the voice-independent ACSS rate value of a voice.'''
  298.         if speaker not in self._SpeechServer__rateInfo:
  299.             return 50
  300.         (minRate, averageRate, maxRate) = self._SpeechServer__rateInfo[speaker]
  301.         rate = speaker.getParameterValue('rate')
  302.         if rate < averageRate:
  303.             return 50 * (rate - minRate) / (averageRate - minRate)
  304.         if rate > averageRate:
  305.             return 50 + 50 * (rate - averageRate) / (maxRate - averageRate)
  306.         return 50
  307.  
  308.     
  309.     def __setRate(self, speaker, acssRate):
  310.         '''Determines the voice-specific rate setting for the
  311.         voice-independent ACSS rate value.
  312.         '''
  313.         if speaker not in self._SpeechServer__rateInfo:
  314.             return None
  315.         (minRate, averageRate, maxRate) = self._SpeechServer__rateInfo[speaker]
  316.         if acssRate < 50:
  317.             rate = minRate + acssRate * (averageRate - minRate) / 50
  318.         elif acssRate > 50:
  319.             rate = averageRate + (acssRate - 50) * (maxRate - averageRate) / 50
  320.         else:
  321.             rate = averageRate
  322.         speaker.setParameterValue('rate', rate)
  323.  
  324.     
  325.     def __getPitch(self, speaker):
  326.         '''Gets the voice-specific pitch setting for the
  327.            voice-independent ACSS pitch value.
  328.  
  329.         Returns the voice-specific pitch setting.
  330.         '''
  331.         if speaker not in self._SpeechServer__pitchInfo:
  332.             return 5
  333.         (minPitch, averagePitch, maxPitch) = self._SpeechServer__pitchInfo[speaker]
  334.         pitch = speaker.getParameterValue('pitch')
  335.         if pitch < averagePitch:
  336.             return 5 * (pitch - minPitch) / (averagePitch - minPitch)
  337.         if pitch > averagePitch:
  338.             return 5 + 5 * (pitch - averagePitch) / (maxPitch - averagePitch)
  339.         return 5
  340.  
  341.     
  342.     def __setPitch(self, speaker, acssPitch):
  343.         '''Determines the voice-specific pitch setting for the
  344.         voice-independent ACSS pitch value.
  345.         '''
  346.         if speaker not in self._SpeechServer__pitchInfo:
  347.             return None
  348.         (minPitch, averagePitch, maxPitch) = self._SpeechServer__pitchInfo[speaker]
  349.         if acssPitch < 5:
  350.             pitch = minPitch + acssPitch * (averagePitch - minPitch) / 5
  351.         elif acssPitch > 5:
  352.             pitch = averagePitch + (acssPitch - 5) * (maxPitch - averagePitch) / 5
  353.         else:
  354.             pitch = averagePitch
  355.         speaker.setParameterValue('pitch', pitch)
  356.  
  357.     
  358.     def __setVolume(self, speaker, acssGain):
  359.         '''Determines the voice-specific rate setting for the
  360.         voice-independent ACSS rate value.
  361.         '''
  362.         if speaker not in self._SpeechServer__volumeInfo:
  363.             return None
  364.         (minVolume, averageVolume, maxVolume) = self._SpeechServer__volumeInfo[speaker]
  365.         volume = minVolume + acssGain * (maxVolume - minVolume) / 10
  366.         speaker.setParameterValue('volume', volume)
  367.  
  368.     
  369.     def __getSpeaker(self, acss = None):
  370.         voices = settings.voices
  371.         defaultACSS = voices[settings.DEFAULT_VOICE]
  372.         if not acss:
  373.             acss = defaultACSS
  374.         
  375.         if acss.name() in self._SpeechServer__speakers:
  376.             return self._SpeechServer__speakers[acss.name()]
  377.         languages = []
  378.         
  379.         try:
  380.             if ACSS.FAMILY in acss:
  381.                 family = acss[ACSS.FAMILY]
  382.                 languages = [
  383.                     family[speechserver.VoiceFamily.LOCALE]]
  384.             elif ACSS.FAMILY in defaultACSS:
  385.                 family = defaultACSS[ACSS.FAMILY]
  386.                 languages = [
  387.                     family[speechserver.VoiceFamily.LOCALE]]
  388.         except:
  389.             acss.name() in self._SpeechServer__speakers
  390.  
  391.         if len(languages) == 0:
  392.             import locale
  393.             (language, encoding) = locale.getdefaultlocale()
  394.             languages = [
  395.                 language]
  396.         
  397.         voices = self._SpeechServer__driver.getAllVoices()
  398.         foundVoices = []
  399.         for voice in voices:
  400.             match = 0
  401.             for language in languages:
  402.                 match = max(match, _matchLanguage(voice.language, language))
  403.             
  404.             if match == 2:
  405.                 foundVoices.insert(0, voice)
  406.                 continue
  407.             if match:
  408.                 foundVoices.append(voice)
  409.                 continue
  410.         
  411.         if len(foundVoices):
  412.             voices = foundVoices
  413.         else:
  414.             voices = self._SpeechServer__driver.getAllVoices()
  415.         familyName = None
  416.         if ACSS.FAMILY in acss:
  417.             family = acss[ACSS.FAMILY]
  418.             familyName = family[speechserver.VoiceFamily.NAME]
  419.         elif ACSS.FAMILY in defaultACSS:
  420.             family = defaultACSS[ACSS.FAMILY]
  421.             familyName = family[speechserver.VoiceFamily.NAME]
  422.         
  423.         found = False
  424.         for voice in voices:
  425.             if not familyName or voice.name == familyName:
  426.                 found = True
  427.                 break
  428.                 continue
  429.         
  430.         if not found:
  431.             if len(voices) == 0:
  432.                 return None
  433.             voice = voices[0]
  434.         
  435.         s = self._SpeechServer__driver.createSpeaker(voice)
  436.         speaker = _Speaker(s._narrow(GNOME.Speech.Speaker), voice)
  437.         
  438.         try:
  439.             parameters = speaker.getSupportedParameters()
  440.             for parameter in parameters:
  441.                 if parameter.name == 'punctuation mode':
  442.                     speaker.setParameterValue('punctuation mode', 0)
  443.                     break
  444.                     continue
  445.         except:
  446.             pass
  447.  
  448.         speaker.registerCallback(self)
  449.         saveParameters = True
  450.         for existingSpeaker in self._SpeechServer__speakers.values():
  451.             if existingSpeaker.voiceInfo == speaker.voiceInfo:
  452.                 
  453.                 try:
  454.                     self._SpeechServer__rateInfo[speaker] = self._SpeechServer__rateInfo[existingSpeaker]
  455.                 except:
  456.                     pass
  457.  
  458.                 
  459.                 try:
  460.                     self._SpeechServer__pitchInfo[speaker] = self._SpeechServer__pitchInfo[existingSpeaker]
  461.                 except:
  462.                     pass
  463.  
  464.                 
  465.                 try:
  466.                     self._SpeechServer__volumeInfo[speaker] = self._SpeechServer__volumeInfo[existingSpeaker]
  467.                 except:
  468.                     pass
  469.  
  470.                 saveParameters = False
  471.                 break
  472.                 continue
  473.         
  474.         if saveParameters:
  475.             parameters = speaker.getSupportedParameters()
  476.             for parameter in parameters:
  477.                 if parameter.name == 'rate':
  478.                     self._SpeechServer__rateInfo[speaker] = [
  479.                         parameter.min,
  480.                         parameter.current,
  481.                         parameter.max]
  482.                     continue
  483.                 if parameter.name == 'pitch':
  484.                     self._SpeechServer__pitchInfo[speaker] = [
  485.                         parameter.min,
  486.                         parameter.current,
  487.                         parameter.max]
  488.                     continue
  489.                 if parameter.name == 'volume':
  490.                     self._SpeechServer__volumeInfo[speaker] = [
  491.                         parameter.min,
  492.                         parameter.current,
  493.                         parameter.max]
  494.                     continue
  495.             
  496.         
  497.         if ACSS.RATE in acss:
  498.             self._SpeechServer__setRate(speaker, acss[ACSS.RATE])
  499.         
  500.         if ACSS.AVERAGE_PITCH in acss:
  501.             self._SpeechServer__setPitch(speaker, acss[ACSS.AVERAGE_PITCH])
  502.         
  503.         if ACSS.GAIN in acss:
  504.             self._SpeechServer__setVolume(speaker, acss[ACSS.GAIN])
  505.         
  506.         self._SpeechServer__speakers[acss.name()] = speaker
  507.         return speaker
  508.  
  509.     
  510.     def __idleHandler(self):
  511.         '''Called by the gidle thread when there is something to do.
  512.         The goal is to try to do all AT-SPI interactions on the gidle
  513.         thread as a means to help prevent hangs.'''
  514.         (thisId, thisType, offset) = self._SpeechServer__eventQueue.get()
  515.         offset = self._SpeechServer__adjustTextCharIndex(offset)
  516.         if self._SpeechServer__sayAll:
  517.             if self._SpeechServer__sayAll.idForCurrentContext == thisId:
  518.                 context = self._SpeechServer__sayAll.currentContext
  519.                 if thisType == GNOME.Speech.speech_callback_speech_started:
  520.                     context.currentOffset = context.startOffset
  521.                     self._SpeechServer__sayAll.progressCallback(self._SpeechServer__sayAll.currentContext, speechserver.SayAllContext.PROGRESS)
  522.                 elif thisType == GNOME.Speech.speech_callback_speech_progress:
  523.                     context.currentOffset = context.startOffset + offset
  524.                     self._SpeechServer__sayAll.progressCallback(self._SpeechServer__sayAll.currentContext, speechserver.SayAllContext.PROGRESS)
  525.                 elif thisType == GNOME.Speech.speech_callback_speech_ended:
  526.                     
  527.                     try:
  528.                         while True:
  529.                             (self._SpeechServer__sayAll.currentContext, acss) = self._SpeechServer__sayAll.utteranceIterator.next()
  530.                             utterance = self._SpeechServer__sayAll.currentContext.utterance
  531.                             logLine = "SPEECH OUTPUT: '" + utterance + "'"
  532.                             debug.println(debug.LEVEL_INFO, logLine)
  533.                             log.info(logLine)
  534.                             if utterance and len(utterance) and not utterance.isspace():
  535.                                 self._SpeechServer__sayAll.idForCurrentContext = self._SpeechServer__speak(utterance, acss)
  536.                                 break
  537.                                 continue
  538.                     except StopIteration:
  539.                         self._SpeechServer__isSpeaking = False
  540.                         context.currentOffset = context.endOffset
  541.                         self._SpeechServer__sayAll.progressCallback(self._SpeechServer__sayAll.currentContext, speechserver.SayAllContext.COMPLETED)
  542.                         self._SpeechServer__sayAll = None
  543.                     except:
  544.                         None<EXCEPTION MATCH>StopIteration
  545.                     
  546.  
  547.                 None<EXCEPTION MATCH>StopIteration
  548.             
  549.         
  550.         rerun = True
  551.         self._SpeechServer__gidleLock.acquire()
  552.         if self._SpeechServer__eventQueue.empty():
  553.             self._SpeechServer__gidleId = 0
  554.             rerun = False
  555.         
  556.         self._SpeechServer__gidleLock.release()
  557.         return rerun
  558.  
  559.     
  560.     def notify(self, progressType, utteranceId, offset):
  561.         '''Called by GNOME Speech when the GNOME Speech driver generates
  562.         a callback.  This is for internal use only.
  563.  
  564.         Arguments:
  565.         - progressType:  one of GNOME.Speech.speech_callback_speech_started,
  566.                          GNOME.Speech.speech_callback_speech_progress,
  567.                          GNOME.Speech.speech_callback_speech_ended
  568.         - utteranceId:   the id of the utterance (returned by say)
  569.         - offset:        the character offset into the utterance (for progress)
  570.         '''
  571.         if progressType == GNOME.Speech.speech_callback_speech_started:
  572.             self._SpeechServer__isSpeaking = True
  573.         elif progressType == GNOME.Speech.speech_callback_speech_progress:
  574.             self._SpeechServer__isSpeaking = True
  575.         elif progressType == GNOME.Speech.speech_callback_speech_ended and not (self._SpeechServer__sayAll):
  576.             self._SpeechServer__isSpeaking = False
  577.         
  578.         if self._SpeechServer__sayAll:
  579.             self._SpeechServer__gidleLock.acquire()
  580.             self._SpeechServer__eventQueue.put((utteranceId, progressType, offset))
  581.             if not self._SpeechServer__gidleId:
  582.                 if settings.gilSleepTime:
  583.                     time.sleep(settings.gilSleepTime)
  584.                 
  585.                 self._SpeechServer__gidleId = gobject.idle_add(self._SpeechServer__idleHandler)
  586.             
  587.             self._SpeechServer__gidleLock.release()
  588.         
  589.  
  590.     
  591.     def getInfo(self):
  592.         '''Returns [driverName, serverId]
  593.         '''
  594.         return [
  595.             self._SpeechServer__driverName,
  596.             self._SpeechServer__iid]
  597.  
  598.     
  599.     def getVoiceFamilies(self):
  600.         '''Returns a list of speechserver.VoiceFamily instances
  601.         representing all the voice families known by the speech server.
  602.         '''
  603.         families = []
  604.         
  605.         try:
  606.             for voice in self._SpeechServer__driver.getAllVoices():
  607.                 props = {
  608.                     speechserver.VoiceFamily.NAME: voice.name,
  609.                     speechserver.VoiceFamily.LOCALE: voice.language }
  610.                 families.append(speechserver.VoiceFamily(props))
  611.         except:
  612.             debug.printException(debug.LEVEL_SEVERE)
  613.  
  614.         return families
  615.  
  616.     
  617.     def queueText(self, text = '', acss = None):
  618.         '''Adds the text to the queue.
  619.  
  620.         Arguments:
  621.         - text: text to be spoken
  622.         - acss: acss.ACSS instance; if None,
  623.                 the default voice settings will be used.
  624.                 Otherwise, the acss settings will be
  625.                 used to augment/override the default
  626.                 voice settings.
  627.  
  628.         Output is produced by the next call to speak.
  629.         '''
  630.         self.speak(text, acss)
  631.  
  632.     
  633.     def queueTone(self, pitch = 440, duration = 50):
  634.         '''Adds a tone to the queue.
  635.  
  636.         Output is produced by the next call to speak.
  637.         '''
  638.         pass
  639.  
  640.     
  641.     def queueSilence(self, duration = 50):
  642.         '''Adds silence to the queue.
  643.  
  644.         Output is produced by the next call to speak.
  645.         '''
  646.         pass
  647.  
  648.     
  649.     def speakCharacter(self, character, acss = None):
  650.         '''Speaks a single character immediately.
  651.  
  652.         Arguments:
  653.         - character: text to be spoken
  654.         - acss:      acss.ACSS instance; if None,
  655.                      the default voice settings will be used.
  656.                      Otherwise, the acss settings will be
  657.                      used to augment/override the default
  658.                      voice settings.
  659.         '''
  660.         chname = chnames.getCharacterName(character)
  661.         if orca_state.activeScript and orca_state.usePronunciationDictionary:
  662.             chname = orca_state.activeScript.adjustForPronunciation(chname)
  663.         
  664.         self.speak(chname, acss)
  665.  
  666.     
  667.     def speakUtterances(self, utterances, acss = None, interrupt = True):
  668.         '''Speaks the given list of utterances immediately.
  669.  
  670.         Arguments:
  671.         - utterances: list of strings to be spoken
  672.         - acss:       acss.ACSS instance; if None,
  673.                       the default voice settings will be used.
  674.                       Otherwise, the acss settings will be
  675.                       used to augment/override the default
  676.                       voice settings.
  677.         - interrupt: if True, stop any speech currently in progress.
  678.         '''
  679.         i = 0
  680.         for text in utterances:
  681.             if len(text):
  682.                 if interrupt:
  683.                     pass
  684.                 self.speak(text, acss, i == 0)
  685.             
  686.             i += 1
  687.         
  688.  
  689.     
  690.     def __adjustTextCharIndex(self, offset):
  691.         '''Get the original character index into the text string (before
  692.         the string was adjusted for verbalized punctuation.
  693.  
  694.         Arguments:
  695.         - offset: character offset into text string
  696.  
  697.         Returns the equivalent character index into the original text string.
  698.         '''
  699.         equivalentIndex = 0
  700.         for i in range(0, len(self.textCharIndices)):
  701.             equivalentIndex = i
  702.             if self.textCharIndices[i] >= offset:
  703.                 break
  704.                 continue
  705.         
  706.         return equivalentIndex
  707.  
  708.     
  709.     def __addVerbalizedPunctuation(self, oldText):
  710.         '''Depending upon the users verbalized punctuation setting,
  711.         adjust punctuation symbols in the given text to their pronounced
  712.         equivalents. The pronounced text will either replace the
  713.         punctuation symbol or be inserted before it. In the latter case,
  714.         this is to retain spoken prosity.
  715.  
  716.         If we are moving around by single characters, then always speak
  717.         the punctuation. We try to detect this by looking for just a
  718.         single character being spoken.
  719.  
  720.         Arguments:
  721.         - oldText:      text to be parsed for punctuation.
  722.  
  723.         Returns a text string with the punctuation symbols adjusted accordingly.
  724.         '''
  725.         oldText = oldText.replace('...', _(' dot dot dot'), 1)
  726.         oldText = oldText.replace('\xe2\x80\xa6', _(' dot dot dot'), 1)
  727.         oldText = oldText.decode('UTF-8')
  728.         removeNewLines = True
  729.         if orca_state.lastInputEvent and 'event_string' in orca_state.lastInputEvent.__dict__:
  730.             lastKey = orca_state.lastInputEvent.event_string
  731.             if lastKey == 'Left' or lastKey == 'Right':
  732.                 removeNewLines = False
  733.             
  734.         
  735.         if removeNewLines:
  736.             oldText = oldText.replace('\n', '', 1)
  737.         
  738.         self.textCharIndices = []
  739.         style = settings.verbalizePunctuationStyle
  740.         newText = ''
  741.         for i in range(0, len(oldText)):
  742.             self.textCharIndices.append(len(newText))
  743.             
  744.             try:
  745.                 (level, action) = punctuation_settings.getPunctuationInfo(oldText[i])
  746.                 isPrev = isNext = isSpecial = False
  747.                 if i > 0:
  748.                     isPrev = not oldText[i - 1].isspace()
  749.                 
  750.                 if i < len(oldText) - 1:
  751.                     isNext = not oldText[i + 1].isspace()
  752.                 
  753.                 if isPrev and isNext:
  754.                     pass
  755.                 isSpecial = oldText[i] == '.'
  756.                 prevCharMatches = nextCharMatches = False
  757.                 if orca_state.activeScript:
  758.                     currencySymbols = orca_state.activeScript.getUnicodeCurrencySymbols()
  759.                 
  760.                 if i == 0:
  761.                     prevCharMatches = True
  762.                 
  763.                 if i > 0:
  764.                     prevCharMatches = oldText[i - 1].isspace()
  765.                 
  766.                 if i < len(oldText) - 1:
  767.                     if not oldText[i + 1].isdigit():
  768.                         pass
  769.                     nextCharMatches = oldText[i + 1] in currencySymbols
  770.                 
  771.                 if oldText[i] == '-' and style != settings.PUNCTUATION_STYLE_NONE and prevCharMatches and nextCharMatches:
  772.                     if isPrev:
  773.                         newText += ' '
  774.                     
  775.                     newText += _('minus')
  776.                 elif len(oldText) == 1 and isSpecial or style <= level:
  777.                     if isPrev:
  778.                         newText += ' '
  779.                     
  780.                     newText += chnames.getCharacterName(oldText[i])
  781.                     if action == punctuation_settings.PUNCTUATION_INSERT and not isNext:
  782.                         newText += oldText[i].encode('UTF-8')
  783.                     
  784.                     if isNext:
  785.                         newText += ' '
  786.                     
  787.                 else:
  788.                     newText += oldText[i].encode('UTF-8')
  789.             continue
  790.             if len(oldText) == 1:
  791.                 newText += chnames.getCharacterName(oldText[i])
  792.             else:
  793.                 newText += oldText[i].encode('UTF-8')
  794.  
  795.         
  796.         return newText
  797.  
  798.     
  799.     def __speak(self, text = None, acss = None, interrupt = True):
  800.         '''Speaks all queued text immediately.  If text is not None,
  801.         it is added to the queue before speaking.
  802.  
  803.         Arguments:
  804.         - text:      optional text to add to the queue before speaking
  805.         - acss:      acss.ACSS instance; if None,
  806.                      the default voice settings will be used.
  807.                      Otherwise, the acss settings will be
  808.                      used to augment/override the default
  809.                      voice settings.
  810.         - interrupt: if True, stops any speech in progress before
  811.                      speaking the text
  812.  
  813.         Returns an id of the thing being spoken or -1 if nothing is to
  814.         be spoken.
  815.         '''
  816.         if not settings.enableSpeech:
  817.             return -1
  818.         speaker = self._SpeechServer__getSpeaker(acss)
  819.         if acss and ACSS.RATE not in acss:
  820.             voices = settings.voices
  821.             defaultACSS = voices[settings.DEFAULT_VOICE]
  822.             if ACSS.RATE in defaultACSS:
  823.                 self._SpeechServer__setRate(speaker, defaultACSS[ACSS.RATE])
  824.             
  825.         
  826.         if not text:
  827.             if interrupt:
  828.                 speech.stop()
  829.             
  830.             return -1
  831.         text = self._SpeechServer__addVerbalizedPunctuation(text)
  832.         
  833.         try:
  834.             self._SpeechServer__lastText = [
  835.                 text,
  836.                 acss]
  837.             self._SpeechServer__isSpeaking = True
  838.             return speaker.say(text)
  839.         except:
  840.             text
  841.             debug.printException(debug.LEVEL_SEVERE)
  842.             debug.println(debug.LEVEL_SEVERE, 'Restarting speech...')
  843.             self.reset()
  844.             return -1
  845.  
  846.  
  847.     
  848.     def speak(self, text = None, acss = None, interrupt = True):
  849.         '''Speaks all queued text immediately.  If text is not None,
  850.         it is added to the queue before speaking.
  851.  
  852.         Arguments:
  853.         - text:      optional text to add to the queue before speaking
  854.         - acss:      acss.ACSS instance; if None,
  855.                      the default voice settings will be used.
  856.                      Otherwise, the acss settings will be
  857.                      used to augment/override the default
  858.                      voice settings.
  859.         - interrupt: if True, stops any speech in progress before
  860.                      speaking the text
  861.         '''
  862.         if self._SpeechServer__sayAll:
  863.             self.stop()
  864.         
  865.         if not acss and text and text.isupper():
  866.             
  867.             try:
  868.                 acss = orca_state.activeScript.voices[settings.UPPERCASE_VOICE]
  869.  
  870.         
  871.         self._SpeechServer__speak(text, acss, interrupt)
  872.  
  873.     
  874.     def isSpeaking(self):
  875.         '''"Returns True if the system is currently speaking.'''
  876.         return self._SpeechServer__isSpeaking
  877.  
  878.     
  879.     def sayAll(self, utteranceIterator, progressCallback):
  880.         '''Iterates through the given utteranceIterator, speaking
  881.         each utterance one at a time.
  882.  
  883.         Arguments:
  884.         - utteranceIterator: iterator/generator whose next() function
  885.                              returns a new string to be spoken
  886.         - progressCallback:  called as progress is made
  887.         '''
  888.         
  889.         try:
  890.             (context, acss) = utteranceIterator.next()
  891.             logLine = "SPEECH OUTPUT: '" + context.utterance + "'"
  892.             debug.println(debug.LEVEL_INFO, logLine)
  893.             log.info(logLine)
  894.             self._SpeechServer__sayAll = _SayAll(utteranceIterator, context, self._SpeechServer__speak(context.utterance, acss), progressCallback)
  895.         except StopIteration:
  896.             pass
  897.  
  898.  
  899.     
  900.     def increaseSpeechPitch(self, step = 0.5):
  901.         '''Increases the speech pitch for the default voice.
  902.  
  903.         Arguments:
  904.         - step: the pitch step increment.
  905.         '''
  906.         voices = settings.voices
  907.         acss = voices[settings.DEFAULT_VOICE]
  908.         speaker = self._SpeechServer__getSpeaker(acss)
  909.         pitchDelta = settings.speechPitchDelta
  910.         
  911.         try:
  912.             pitch = min(10, self._SpeechServer__getPitch(speaker) + pitchDelta)
  913.             acss[ACSS.AVERAGE_PITCH] = pitch
  914.             self._SpeechServer__setPitch(speaker, pitch)
  915.             debug.println(debug.LEVEL_CONFIGURATION, 'speech.increaseSpeechPitch: pitch is now  %d' % pitch)
  916.             self.speak(_('higher.'))
  917.         except:
  918.             debug.printException(debug.LEVEL_SEVERE)
  919.  
  920.  
  921.     
  922.     def decreaseSpeechPitch(self, step = 0.5):
  923.         '''Decreases the speech pitch for the default voice.
  924.  
  925.         Arguments:
  926.         - step: the pitch step decrement.
  927.         '''
  928.         voices = settings.voices
  929.         acss = voices[settings.DEFAULT_VOICE]
  930.         speaker = self._SpeechServer__getSpeaker(acss)
  931.         pitchDelta = settings.speechPitchDelta
  932.         
  933.         try:
  934.             pitch = max(1, self._SpeechServer__getPitch(speaker) - pitchDelta)
  935.             acss[ACSS.AVERAGE_PITCH] = pitch
  936.             self._SpeechServer__setPitch(speaker, pitch)
  937.             debug.println(debug.LEVEL_CONFIGURATION, 'speech.decreaseSpeechPitch: pitch is now  %d' % pitch)
  938.             self.speak(_('lower.'))
  939.         except:
  940.             debug.printException(debug.LEVEL_SEVERE)
  941.  
  942.  
  943.     
  944.     def increaseSpeechRate(self, step = 5):
  945.         '''Increases the speech rate.
  946.  
  947.         [[[TODO: WDW - this is a hack for now.  Need to take min/max
  948.         values in account, plus also need to take into account that
  949.         different engines provide different rate ranges.]]]
  950.         '''
  951.         voices = settings.voices
  952.         acss = voices[settings.DEFAULT_VOICE]
  953.         speaker = self._SpeechServer__getSpeaker(acss)
  954.         rateDelta = settings.speechRateDelta
  955.         
  956.         try:
  957.             rate = min(100, self._SpeechServer__getRate(speaker) + rateDelta)
  958.             acss[ACSS.RATE] = rate
  959.             self._SpeechServer__setRate(speaker, rate)
  960.             debug.println(debug.LEVEL_CONFIGURATION, 'speech.increaseSpeechRate: rate is now  %d' % rate)
  961.             self.speak(_('faster.'))
  962.         except:
  963.             debug.printException(debug.LEVEL_SEVERE)
  964.  
  965.  
  966.     
  967.     def decreaseSpeechRate(self, step = 5):
  968.         '''Decreases the rate of speech for the given ACSS.  If
  969.         acssName is None, the rate decrease will be applied to all
  970.         known ACSSs.
  971.  
  972.         [[[TODO: WDW - this is a hack for now.  Need to take min/max
  973.         values in account, plus also need to take into account that
  974.         different engines provide different rate ranges.]]]
  975.  
  976.         Arguments:
  977.         -acssName: the ACSS whose speech rate should be decreased
  978.         '''
  979.         voices = settings.voices
  980.         acss = voices[settings.DEFAULT_VOICE]
  981.         speaker = self._SpeechServer__getSpeaker(acss)
  982.         rateDelta = settings.speechRateDelta
  983.         
  984.         try:
  985.             rate = max(1, self._SpeechServer__getRate(speaker) - rateDelta)
  986.             acss[ACSS.RATE] = rate
  987.             self._SpeechServer__setRate(speaker, rate)
  988.             debug.println(debug.LEVEL_CONFIGURATION, 'speech.decreaseSpeechRate: rate is now  %d' % rate)
  989.             self.speak(_('slower.'))
  990.         except:
  991.             debug.printException(debug.LEVEL_SEVERE)
  992.  
  993.  
  994.     
  995.     def stop(self):
  996.         '''Stops ongoing speech and flushes the queue.'''
  997.         if self._SpeechServer__sayAll:
  998.             self._SpeechServer__sayAll.progressCallback(self._SpeechServer__sayAll.currentContext, speechserver.SayAllContext.INTERRUPTED)
  999.             self._SpeechServer__sayAll = None
  1000.         
  1001.         for name in self._SpeechServer__speakers.keys():
  1002.             
  1003.             try:
  1004.                 self._SpeechServer__speakers[name].stop()
  1005.             continue
  1006.             continue
  1007.  
  1008.         
  1009.         self._SpeechServer__isSpeaking = False
  1010.  
  1011.     
  1012.     def shutdown(self):
  1013.         '''Shuts down the speech engine.'''
  1014.         if self._SpeechServer__iid in SpeechServer._SpeechServer__activeServers:
  1015.             for speaker in self._SpeechServer__speakers.values():
  1016.                 speaker.stop()
  1017.                 speaker.unref()
  1018.             
  1019.             self._SpeechServer__speakers = { }
  1020.             
  1021.             try:
  1022.                 self._SpeechServer__driver.unref()
  1023.             except:
  1024.                 pass
  1025.  
  1026.             self._SpeechServer__driver = None
  1027.             del SpeechServer._SpeechServer__activeServers[self._SpeechServer__iid]
  1028.         
  1029.  
  1030.     
  1031.     def reset(self, text = None, acss = None):
  1032.         '''Resets the speech engine.'''
  1033.         if time.time() - self._SpeechServer__lastResetTime < 20:
  1034.             debug.println(debug.LEVEL_SEVERE, 'Something looks wrong with speech.  Aborting.')
  1035.             debug.printStack(debug.LEVEL_ALL)
  1036.             orca.die(50)
  1037.         else:
  1038.             self._SpeechServer__lastResetTime = time.time()
  1039.         speakers = self._SpeechServer__speakers
  1040.         self.shutdown()
  1041.         servers = bonobo.activation.query("repo_ids.has('IDL:GNOME/Speech/SynthesisDriver:0.3')")
  1042.         for server in servers:
  1043.             if server.iid == self._SpeechServer__iid:
  1044.                 
  1045.                 try:
  1046.                     self._SpeechServer__driver = self._SpeechServer__activateDriver(self._SpeechServer__iid)
  1047.                     self._SpeechServer__speakers = { }
  1048.                     for name in speakers.keys():
  1049.                         self._SpeechServer__getSpeaker(speakers[name])
  1050.                     
  1051.                     if text:
  1052.                         self.speak(text, acss)
  1053.                     
  1054.                 debug.printException(debug.LEVEL_SEVERE)
  1055.                 self._SpeechServer__driver = None
  1056.  
  1057.                 continue
  1058.         
  1059.  
  1060.  
  1061.